/*********************************************************************************
 *      Copyright:  (C) 2024 YunQi
 *                  All rights reserved.
 *
 *       Filename:  mqtt.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(25/04/24)
 *         Author:  denglen <Dengleen@outlook.com>
 *      ChangeLog:  1, Release initial version on "25/04/24 06:17:58"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <mosquitto.h>
#include <libgen.h>
#include <getopt.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>

#include "ds18b20.h"
#include "logger.h"
#include "sht20.h"
#include "adc_mq2.h"
#include "adc_light.h"
#include "mqtt.h"
#include "conf.h"
#include "pwm.h"
#include "led.h"


int g_stop = 0;
mqtt_ctx_t              mqtt_ctx;
int                     retain = 0;
int                     mid, mid1;


void mqtt_clean(struct mosquitto *mosq);
static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg);
static inline void print_usage(char *progname);
void sig_handler(int signum);


int main(int argc, char **argv)
{
	struct mosquitto       *mosq;
	int                     session = true;

	float                   rh;
	float                   roomtemp;
	float                   smokescope;
	float                   light = 0;

	int                     option = 0;
	char                   *ini_path="config.ini";

	time_t                  last_time, end_time;
	double                  elapsed_time;
	int                     rv;	
	int                     opt;
	int                     daemon_run=0;
	int                     stime;
	char                   *progname = NULL;

	char                   *logfile="sock_client.log";
	int                     loglevel=LOG_LEVEL_INFO;
	int                     logsize=10;
	struct option              long_options[] =
	{
		{"daemon", no_argument, NULL, 'b'},
		{"logger", no_argument, NULL, 'd'},
		{"time", required_argument, NULL, 't'},
		{"option", required_argument, NULL, 'o'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	progname = basename(argv[0]);
	while((opt = getopt_long(argc, argv, "bt:do:h", long_options, NULL)) != -1)
	{
		switch(opt)
		{
			case'b':
				daemon_run = 1;
				break;

			case't':
				stime =atoi(optarg);
				break;

			case'd':
				daemon_run = 0;
				logfile="console";
				loglevel=LOG_LEVEL_DEBUG;
				break;

			case'o':
				option=atoi(optarg);
				break;

			case'h':
				print_usage(progname);
				return EXIT_SUCCESS;

			default:
				break;
		}
	}
	if( log_open(logfile, loglevel, logsize, THREAD_LOCK_NONE) < 0 )
	{
		fprintf(stderr, "Initial log system failed\n");
		return -2;
	}

	log_debug("program start running.\n");


	if(daemon_run)
	{
		daemon(1, 0);
	}

	if(get_mqtt_parameter1(ini_path, &mqtt_ctx, option) < 0)
	{
		log_error("get mqtt's parameter failured!");
		return -3;
	}

	log_debug("mqtt_ctx.hostname = %s\n", mqtt_ctx.hostname);
	log_debug("mqtt_ctx.clientid = %s\n", mqtt_ctx.clientid);
	log_debug("mqtt_ctx.username = %s\n", mqtt_ctx.username);
	log_debug("mqtt_ctx.password = %s\n", mqtt_ctx.password);
	log_debug("mqtt_ctx.port = %d\n", mqtt_ctx.port);

	log_debug("mqtt_ctx.pub_topic = %s\n", mqtt_ctx.pub_topic);
	log_debug("mqtt_ctx.sub_topic = %s\n", mqtt_ctx.sub_topic);
	log_debug("mqtt_ctx.keepalive = %d\n", mqtt_ctx.keepalive);
	log_debug("mqtt_ctx.qos = %d\n", mqtt_ctx.qos);


	if(led_init() < 0)
	{
		log_error("led initial failure\n");
		return -4;
	}

	mosquitto_lib_init();
	mosq = mosquitto_new(mqtt_ctx.clientid, session, NULL);

	if (mosquitto_username_pw_set(mosq, mqtt_ctx.username, mqtt_ctx.password) != MOSQ_ERR_SUCCESS)
	{
		log_error("mqtt connect parameters set failure\n");
		goto cleanup;
	}
	log_debug("mqtt connect parameters set OK\n");


	if (mosquitto_connect(mosq, mqtt_ctx.hostname, mqtt_ctx.port, mqtt_ctx.keepalive) != MOSQ_ERR_SUCCESS)
	{
		log_error("connect server failure!\n");
		goto cleanup;
	}
	log_debug("Connect to the Internet of Things platform successfully!\n");


	if (mosquitto_loop_start(mosq) != MOSQ_ERR_SUCCESS)
	{
		log_error("mosquitto_loop_start_failure\n");
		goto cleanup;
	}


	mosquitto_message_callback_set(mosq, my_message_callback);

	if (mosquitto_subscribe(mosq, &mid, mqtt_ctx.sub_topic, mqtt_ctx.qos) != MOSQ_ERR_SUCCESS)
	{
		log_error("mosquitto subsribe failure\n");
		goto cleanup;
	}
	log_debug("subscribe successfully\n");

	signal(SIGINT,  sig_handler);
	signal(SIGTERM, sig_handler);

	last_time=0;
	while( !g_stop )
	{
		if((rv = get_smokescope(&smokescope)) < 0)//实时采集烟雾浓度
		{
			log_error("get smokescope failure:%d\n", rv);
			continue;
		}
		log_debug("get smokescope successfully\n");

		if(smokescope>=20)//烟雾浓度超过20%
		{
			buzzer("1");//蜂鸣器报警
			log_info("Smoke concentration exceeds tne threshold!\n");
			memset(mqtt_ctx.payload, 0, sizeof(mqtt_ctx.payload));
			if(option==1)
			{
				snprintf(mqtt_ctx.payload, sizeof(mqtt_ctx.payload),
				"{\"services\": [{\"service_id\": \"service\",\
				\"properties\": {\"smokescope\": %.2f}}]}", smokescope);
			}

			if(option==2)
			{
				snprintf(mqtt_ctx.payload, sizeof(mqtt_ctx.payload),
				"{\"params\":{\"smokescope\":%.2f}}", smokescope);
			}
			log_info("pub messages: %s\n", mqtt_ctx.payload);

			if (mosquitto_publish(mosq, &mid1, mqtt_ctx.pub_topic, strlen(mqtt_ctx.payload), 
					mqtt_ctx.payload, mqtt_ctx.qos, retain) != MOSQ_ERR_SUCCESS)
				//将数据上传阿里云平台
			{
				log_error("mosquitto publish data failure!\n");
				continue;
			}
		}
		else
		{
			buzzer("0");//否则蜂鸣器不报警
		}

		time(&end_time);
		if((elapsed_time = difftime(end_time, last_time)) >= stime)
			//每过半小时采集一次数据并将数据上传阿里云
		{

			if((rv = sht2x_get_temperature_humidity(&roomtemp, &rh)) < 0)//采集温湿度
			{
				log_error("get temperrature failure: %d\n", rv);
				continue;
			}
			log_debug("Get temperature successflly!\n");
			log_debug("Get humidity successfully!\n");


			if((rv = get_light_intensity(&light)) < 0)//采集光强
			{
				log_error("get lightlux failure: %d\n", rv);
				continue;
			}
			log_debug("Get lightlux successfully!\n");		

			memset(mqtt_ctx.payload, 0, sizeof(mqtt_ctx.payload));

			if(option==1)
			{
				snprintf(mqtt_ctx.payload, sizeof(mqtt_ctx.payload),
				"{\"services\": [{\"service_id\": \"service\",\
				\"properties\": {\"RoomTemp\": %.2f,\"RelativeHumidity\": %.2f,\
				\"smokescope\": %.2f,\"LightLux\": %.2f}}]}", 
				roomtemp, rh, smokescope, light);
			}

			if(option==2)
			{
				snprintf(mqtt_ctx.payload, sizeof(mqtt_ctx.payload),
				"{\"params\":{\"RoomTemp\":%.2f,\"RelativeHumidity\":%.2f,\
				\"smokescope\":%.2f,\"LightLux\":%.2f}}", 
				roomtemp, rh, smokescope, light);
			}
			log_info("pub messages: %s\n", mqtt_ctx.payload);

			if (mosquitto_publish(mosq, &mid1, mqtt_ctx.pub_topic, strlen(mqtt_ctx.payload), 
						mqtt_ctx.payload, mqtt_ctx.qos, retain) != MOSQ_ERR_SUCCESS)//发布消息
			{
				log_error("mosquitto publish data failure!\n");
				continue;
			}

			last_time=end_time;
		}
		sleep(8);
	}

cleanup:
	led_release();
	mqtt_clean(mosq);
	buzzer("0");
	log_info("source release completed!\n");
	log_close();
	return 0;
}


static inline void print_usage(char *progname)
{
	printf("Usage: %s [OPTION]...\n",progname);

	printf(" %s is a socket server program, which used to verify client and echo back string from it\n",progname);

	printf("\nMandatroy arguments to long options are mandatroy for short options too:\n");

	printf(" -b[daemon ] set program running on background\n");
	printf(" -d[debug ] print logger's data on the screen\n");
	printf(" -h[help ] Display this help information\n");

	printf("\nExample: %s -t 5 -d\n",progname);

	return ;
}


void mqtt_clean(struct mosquitto *mosq)
{
	mosquitto_destroy(mosq);
	mosquitto_lib_cleanup;
	return ;
}


static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
	/* 负责接收阿里云平台下发消息，控制灯的亮灭 */
	char *ptr=NULL;
	char *str="LightSwitc";
	char  buf[2];
	int   i=3;

	ptr = strstr((char *)msg->payload, str);
	//log_info("sub messages: %s\n", (char *)msg->payload);

	if(ptr == NULL)
	{
		;
	}
	else
	{
		log_debug("'LightSwitc' found in %d\n", ptr-(char *)msg->payload);
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof(buf), "%s", ptr+13);
		log_info("sub messages: %s\n", (char *)msg->payload);
		if(strcmp("1", buf) == 0)
			turn_led(LED_R, ON);
		else
			turn_led(LED_R, OFF);
		log_debug("%s\n", buf);

#if 1	
		snprintf(mqtt_ctx.payload, sizeof(mqtt_ctx.payload),
		"{\"method\":\"thing.service.property.post\",\"id\":\"1149211576\",\
		\"params\":{\"LightSwitch\":%s},\"version\":\"1.0.0\"}",
		buf);

		if (mosquitto_publish(mosq, &mid1, mqtt_ctx.pub_topic, strlen(mqtt_ctx.payload), 
					mqtt_ctx.payload, mqtt_ctx.qos, retain) != MOSQ_ERR_SUCCESS)
		{
			log_error("mosquitto publish data failure!\n");
		}
		log_info("pub messages: %s\n", mqtt_ctx.payload);
#endif

	}

	return ;
}

void sig_handler(int signum)
{
	switch(signum)
	{
		case SIGINT:
			g_stop = 1;
			break;

		case SIGTERM:
			g_stop = 1;
			break;

		default:
			break;
	}

	return ;
}
